<?php



class CommonApi extends ApiBase{


	/**
	 * 构造函数，初始化插件
	 */
	public function __construct() {
		parent::__construct();
	}



	private $maxSize = 4194304; //4*1024*1024;

	private $mine = array(
		'application/rar'=>array('5261','rar'),
		'application/x-rar-compressed'=>array('5261','rar'),
		'application/x-zip-compressed'=>array('504b','zip'),
		'application/x-compressed'=>array('504b','zip'),
		'application/zip'=>array('504b','zip'),
		'application/octet-stream'=>array('504b','zip'),
		'image/gif'=>array('4749','gif'),
		'image/jpeg'=>array('ffd8','jpg'),
		'image/pjpeg'=>array('ffd8','jpg'),
		'image/png'=>array('8950','png'),
		'image/x-png'=>array('8950','png'));
	
	public function getIpDetail() {
		$arr = array();
		$arr['country'] = $_POST['ip1'];
		$arr['province'] = $_POST['ip2'];
		$arr['city'] = $_POST['ip3'];

		return $arr;
	}

	public function getFileMime($file){
		if(!file_exists($file)){
			throw new PException("找不到文件");
		}
		$fhandle = fopen($file,"r+");
		$str = fread($fhandle , 2);
		fclose($fhandle);		
		$str = unpack('H*',$str);
		
		return $str[1];
		
	}	
	public function upload($name){
		
		if(!isset($_FILES[$name])){
			throw new PException("没有文件被上传");
		}
		if($_FILES[$name]['size']>$this->maxSize){
			throw new PException("上传的文件超过最大尺寸");
		}
		if(!isset($this->mine[$_FILES[$name]['type']])){
			throw new PException("只能上传rar，zip，gif，jpg，png文件！");
		}
		switch ($_FILES[$name]["error"]) {
			case 0:break;
			case 1:throw new PException("上传文件超过预定义尺寸(".ini_get("upload_max_filesize").")");break;
			case 2:throw new PException("上传文件尺寸超过表单定义");break;
			case 3:throw new PException("未完整上传");break;
			case 4:throw new PException("没有文件上传");break;
			case 6:throw new PException("找不到临时目录");break;
			case 7:throw new PException("写入磁盘错误");break;
			default:throw new PException("未知错误");
		}
		$rs = $_FILES[$name];
		$rs['extend'] = $this->mine[$_FILES[$name]['type']][1];
		
		if($this->mine[$_FILES[$name]['type']][0] != $this->getFileMime($rs['tmp_name'])){
			throw new PException("上传的文件后缀和文件类型不符合");
		}
		
//		unset($rs['name']);
		unset($rs['error']);
//		unset($rs['type']);
		
		return $rs;
	}


	/**
	 * 可以设定超时时间，如果超时再次抓取次数
	 */
	public function download($url, $file, $timeout = 10, $repeat = 1){
		
		if (substr($file, -1) == '/' || empty($url)) {
			return n_state(false, '下载失败0！图片地址为空或文件名为一个目录！');
		}
		if (false === ($ch = curl_init())) {
			return n_state(false, '下载失败1！');
		}

		$options = array(
			CURLOPT_USERAGENT 		=> 'Mozilla/5.0 (Windows NT 6.1; rv:11.0) Gecko/20100101 Firefox/11.0',
			CURLOPT_AUTOREFERER 	=> true,
			CURLOPT_FOLLOWLOCATION 	=> true,
			CURLOPT_RETURNTRANSFER	=> true,
			CURLOPT_URL				=> $url,
			CURLOPT_BINARYTRANSFER	=> true,
			CURLOPT_TIMEOUT			=> $timeout,	
		);
	    
		curl_setopt_array($ch, $options);
	    
		$dir = dirname($file);
		if(is_dir($dir)) {
			$this->mkdir($dir, 0755);
		}
		if (($fp = fopen($file, "wb")) === false) {
			return n_state(false, '下载失败2！创建文件失败');
		}
		curl_setopt($ch, CURLOPT_FILE, $fp);
	    
		if (false === curl_exec($ch)) {
			fclose($fp);
			unlink($file);
			return n_state(false, '下载失败3！创建文件失败'.curl_error($ch)); 

		} else {
			fclose($fp);
		}
	    
		$header = curl_getinfo($ch);

		curl_close($ch);

		$result = n_state(TRUE, "下载成功");
		$result['header'] = $header;
	 	 
		return $result;
		
	}

	/**
	 * deep copy,will copy the dir and all the sub dir and files
	 */
	public function ncopy($source,$dest){
		if(file_exists($dest)){
			rename($dest,$dest.date('YmdHis').'-'.rand(0,9).'.bak');
		}
		$this->mkdir(dirname($dest));
		copy($source,$dest);
	}

	public function mkdir($dir,$mode=0700){
		if(!is_dir($dir)){
			if(!is_dir(dirname($dir))){
				$this->mkdir(dirname($dir),$mode);
			}
			if(!mkdir($dir, $mode, true)){
				throw new PException("创建目录失败!");
			}
		}
		return true;
	}
	
	
	public function paging($url,$current,$totalItems,$perpage=20){

		
		$url = !preg_match("/\?.*$/", $url)?$url.'?':$url.'&';
		
		if(empty($totalItems)){
			return '';
		}
		$totalPage = ceil($totalItems/$perpage);
		if($current>$totalPage){
			$current = $totalPage;
		}
		if($current<1){
			$current = 1;
		}
	
		$html = "<a href=\"{$url}\">首页</a>";
		if($current>1){
			$prepage = $current - 1; 
			$html .= "<a href=\"{$url}page={$prepage}\">上一页</a>";
		}
		
		//计算开始和结束间的页
		$start = ($current-3)>0?$current-3:1;
		$end = $start+7;
		
		if($end>$totalPage){
			$end = $totalPage;
			$start = $end - 7;
		}
		//如果点击到末页，让偏移量保持7页
		$start = $start<1?1:$start;
		// echo $start.'=='.$end.'=='.$totalItems;
		for($i=$start;$i<=$end;$i++){
			if($i==$current){
				$html .= "<span>{$i}</span>";
			}else{
				$html .= "<a href=\"{$url}page={$i}\">{$i}</a>";
			}
		}
	
		if($current!=$totalPage){
			$nextpage = $current+1;
			$html .= "<a href=\"{$url}page={$nextpage}\">下一页</a>";
		}
			
		$html .= "<a href=\"{$url}page={$totalPage}\">末页</a>";
	
		return $html;
	}
	
	
	
	/**
	 * 将数组构建成一个树
	 */
	public function reTree(&$data,$rootVal='0',$parentKey='pid'){
		if(!is_array($data)){
			throw new PException("参数必须是数组");
		}
		if(empty($data)){
			return array();
		}
		$rs = array();
		foreach($data as $key=>$val){
			if(!isset($val[$parentKey])){
				throw new PException("找不到parentKey");
			}
			
			if($val[$parentKey]==$rootVal){
				$rs[$key] = $val;
				$rs[$key]['sub'] = $this->reTree($data,$key,$parentKey);
				unset($data[$key]);
				reset($data);
			}

		}
		return $rs;

	}
	/**
	 * 将一个树压缩成一个一维数组
	 */
	public function pressTree($data,$subKey='sub',&$rs=array(),$deep=0){
		if(is_array($data) && !empty($data)){
			foreach($data as $key=>$val){
				$sub = $val[$subKey];
				unset($val[$subKey]);
				
				$rs[$key] = $val;
				$rs[$key]['deep'] = $deep;
				if(!empty($sub) && is_array($sub)){
					$nextDeep = $deep+1;
					$this->pressTree($sub,$subKey,$rs,$nextDeep);
				}
			}
		}
		return $rs;
	}
	
	
	/**
	 * 获取服务器IP地址
	 */
	public function getServerIp(){
		if (isset($_SERVER)){
			if (isset($_SERVER['SERVER_ADDR'])){
				$serverip = $_SERVER['SERVER_ADDR'];
			}else{
				$serverip = '0.0.0.0';
			}
		}else{
			$serverip = getenv('SERVER_ADDR');
		}
		return $serverip;
	}
	/**
	 * 获取服务器IP地址
	 */
	public function getClientIp(){
		$unknown = 'unknown';
		if ( isset($_SERVER['HTTP_X_FORWARDED_FOR']) 
		&& $_SERVER['HTTP_X_FORWARDED_FOR'] 
		&& strcasecmp($_SERVER['HTTP_X_FORWARDED_FOR'], 
		$unknown) ) {  
			$clientip = $_SERVER['HTTP_X_FORWARDED_FOR'];  
		} elseif ( isset($_SERVER['REMOTE_ADDR']) 
		&& $_SERVER['REMOTE_ADDR'] && 
		strcasecmp($_SERVER['REMOTE_ADDR'], $unknown) ) {  
			$clientip = $_SERVER['REMOTE_ADDR'];  
		}
		
		/*  
		处理多层代理的情况  
		或者使用正则方式：$ip = preg_match("/[d.]
		{7,15}/", $ip, $matches) ? $matches[0] : $unknown;  
		*/  
		if (false !== strpos($clientip, ','))  
			$clientip = reset(explode(',', $clientip));
		
		return $clientip;  
	}	
	
	/**
	 * linruiyan@2012-10-10
	 * 构建面包屑
	 */
	static private $crumb = array();
	public function setCrumb($txt, $href = '', $target = ''){
		self::$crumb[] = empty($href) ? $txt : "<a href='{$href}' target='{$target}'>{$txt}</a>";

		return $this;
	}
	public function getCrumb(){

		$rs = "<a href='".n_url("member","index")."'>首页</a>";
		if(!empty(self::$crumb)){
			foreach (self::$crumb as $key => $val) {
				$rs.= "&nbsp;&gt;&nbsp;";
				$rs.= $val;
			}
		}
		return $rs;
	}
	
	/**
	 * linruiyan@2012-10-22
	 * 增加文件的操作，目前需求不是很多，所以先就放在common中，如果需求多在独立为插件
	 */
	public function loadFile($file,$start=0,$end=0){
		if(!file_exists($file)){
			return n_state(FALSE, "读取文件失败:{$dir}");
		}
		$start = intval($start);
		$end = intval($end);
		
		if($end<$start){
			return n_state(FALSE, "读取位必须大于起始位");
		}
		if($start==$end){
			return '';
		}
		
		$fhandle = fopen($file, 'r');
		if(0!=$start){
			fseek($fhandle, $start);
		}
		$rs = fread($fhandle, $end-$start);
		fclose($fhandle);
		return $rs;
		
	}
	/**
	 * linruiyan@2012-10-24 一些情况我们需要按行来读取文件
	 */
	public function loadFileByLine($file,$start,$linenum=0){
		if(!file_exists($file)){
			return n_state(FALSE, "读取文件失败:{$dir}");
		}
		$start = preg_match("/^[1-9]\\d*$/", $start)?$start:0;
		
		// $end = $start+intval($linenum);
// 		
		// if($end<$start){
			// return n_state(FALSE, "读取行数必须大于起始行数");
		// }
		// if($start==$end){
			// return '';
		// }
		$data = '';
		$fhandle = fopen($file, 'r');
		if ($fhandle) {
			fseek($fhandle, $start);
			$i=0;
			 while (!feof($fhandle)) {
				if(++$i>$linenum){
					break;
				}
			 	$buffer = fgets($fhandle, 10*1024*1024);
			 	 $data .= $buffer;
			 }
			$offset = ftell($fhandle);
			 fclose($fhandle);
		}
		return array('offset'=>$offset,'data'=>$data);		
	}
	
	public function curlPost($url,$data,$port=0,$host='', $timeout = 20){
		if(!is_array($data)){
			return n_state(FALSE, "数据必须为数组");
		}
		
		$rs = n_state(TRUE, "请求成功");
		
		$ch = curl_init();
		$options = array(
						CURLOPT_URL => $url,
						// CURLOPT_HEADER => true,
						CURLOPT_RETURNTRANSFER => true,
						// CURLOPT_PORT =>6225,
						CURLOPT_USERAGENT	   => 'Mozilla/5.0 (Windows NT 6.1; rv:11.0) Gecko/20100101 Firefox/11.0', 
						CURLOPT_TIMEOUT	=> $timeout,	 
					);
		curl_setopt_array($ch, $options);

		if(!empty($port)){
			curl_setopt($ch, CURLOPT_PORT, $port);
		}
		if(!empty($host)){
			curl_setopt($ch, CURLOPT_HTTPHEADER, array("Host: {$host}"));
		}

		curl_setopt($ch, CURLOPT_POST, 1);
		curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
				
		$respond = curl_exec($ch);
		$curlRs = curl_getinfo($ch);		
		curl_close($ch);
		$rs['header'] = $curlRs;
		$rs['respond'] = $respond;
		
		return $rs;	
	}
	
	/**
	 * curl get 请求
	 * @param string $url 请求地址
	 * @param int $port 指定连接端口
	 * @param string $host 设置HTTP头字段的host
	 * @param itn $timeout 超时时间 默认2s
	 * 
	 */
	public function curlGet($url,$port=0,$host='', $timeout = 20){
		
		$rs = n_state(TRUE, "请求成功");
		
		$ch = curl_init();
		$options = array(
						CURLOPT_URL => $url,
						CURLOPT_USERAGENT	   => 'Mozilla/5.0 (Windows NT 6.1; rv:11.0) Gecko/20100101 Firefox/11.0',
						CURLOPT_RETURNTRANSFER => 1,
						CURLOPT_BINARYTRANSFER => 1,	  
						CURLOPT_TIMEOUT		   => $timeout,
					);
		curl_setopt_array($ch, $options);
					
		if(!empty($port)){
			curl_setopt($ch, CURLOPT_PORT, $port);
		}
		
		if(!empty($host)){
			curl_setopt($ch, CURLOPT_HTTPHEADER, array("Host: {$host}"));
		}
		
		$respond = curl_exec($ch);
		$curlRs = curl_getinfo($ch);		
		curl_close($ch);
		$rs['header'] = $curlRs;
		$rs['respond'] = $respond;
		
		return $rs;	
	}

	/**
	 * curlPostXml
	 *
	 * POST XML
	 * 
	 * @param  string  $url	  请求的地址
	 * @param  integer $port	 端口
	 * @param  string  $xml	  xml字符串
	 * @param  string  $host	 host
	 * @param  integer $timeout 超时时间
	 * @return array
	 */
	public function curlPostXml($url, $xml, $port = 0,  $host = '', $timeout = 5) {
		if(empty($url) || empty($xml)){
			return n_state(FALSE, "URL 或 xml为空!");
		}
		
		$rs = n_state(TRUE, "请求成功");
		
		$ch = curl_init();
		$options = array(
						CURLOPT_URL => $url,
						CURLOPT_RETURNTRANSFER => true,
						CURLOPT_USERAGENT	   => 'Mozilla/5.0 (Windows NT 6.1; rv:11.0) Gecko/20100101 Firefox/11.0', 
						CURLOPT_TIMEOUT	=> $timeout,	 
					);
		if(!empty($port)){
			curl_setopt($ch, CURLOPT_PORT, $port);
		}

		curl_setopt_array($ch, $options);
		if(!empty($host)){
			curl_setopt($ch, CURLOPT_HTTPHEADER, array("Host: {$host}", 'Content-Type:text/xml'));
		}
		curl_setopt($ch, CURLOPT_POST, 1);
		
		curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
				
		$respond = curl_exec($ch);
		$curlRs = curl_getinfo($ch);		
		curl_close($ch);
		$rs['header'] = $curlRs;
		$rs['respond'] = $respond;
		
		return $rs;	
	}

	/**
	 * 根据ip地址获取地区,$type=1查询纯真ip库，$type<>1走搜狗接口
	 * @param string $ip ip地址
	 * @param int $type	查询接口
	 * @return array
	 */
	public function getIpLocation($ip,$type=1){
		//为空验证
		if(empty($ip)){return array('country'=>'');}
		
		//内网和保留地址处理
		$ip_array = explode('.', $ip);
	 	if(!empty($ip_array)){
	 		//处理私有地址
	 		if($ip_array[0] == '10' || ($ip_array[0] == '172' && intval($ip_array[1]) >= 16 && intval($ip_array[1]) <= 31) || ($ip_array[0] == '192' && $ip_array[1] == '168')){
	 			return array('country'=>'内网地址');
	 		}
	 		//处理保留地址
	 		if($ip_array[0] == '127' || ($ip_array[0] == '169' && $ip_array[1] == '254')){
	 			return array('country'=>'保留地址');
	 		}
	 		//IANA
	 		if(intval($ip_array[0]) >= 224){
	 			return array('country'=>'IANA');
	 		}
	 	 }
		
		//获取ip对应的地区
		if($type == 1){	
			$ipLocation = new IpLocation();
			$ip_addr = $ipLocation->getlocation($ip);
			$location['country'] = mb_convert_encoding($ip_addr['country'],'utf-8','gb2312,gbk,UTF-8,BIG-5');
		}else{
		    $url = 'http://dev.op.sogou-inc.com:9001/ip2loc/' . $ip;
		    $ip_addr = $this->curlGet($url);
		   $location['country'] = mb_convert_encoding($ip_addr['respond'],'utf-8','auto');
		}
		
		if (empty($location)) { $location['country'] = '';}
		
		return $location;
	}

	/**
	 * session编码
	 *
	 * @param unknown_type $data
	 * @return unknown
	 */
	public function unserializesession($data) {
		 $vars=preg_split('/([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff^|]*)\|/',
		 	 	   $data,-1,PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
		// print_r($vars);				  
		 for($i=0; $i<count($vars); $i+=2) $result[$vars[$i]]=unserialize($vars[$i+1]);
		 return $result;
	}
	
	/**
	 * 
	 * 这个星期的星期一
	 * @$timestamp ，某个星期的某一个时间戳，默认为当前时间
	 * @is_return_timestamp ,是否返回时间戳，否则返回时间格式
	 */  
	function thisMonday($timestamp=0,$is_return_timestamp=true){  
		 static $cache ;  
		 $id = $timestamp.$is_return_timestamp;  
		 if(!isset($cache[$id])){  
		 	 if(!$timestamp) $timestamp = time();  
		 	 $monday_date = date('Ymd', $timestamp-86400*date('w',$timestamp)+(date('w',$timestamp)>0?86400:-/*6*86400*/518400));  
		 	 if($is_return_timestamp){  
		 	 	 $cache[$id] = strtotime($monday_date);  
		 	 }else{  
		 	 	 $cache[$id] = $monday_date;  
		 	 }  
		 }  
		 return $cache[$id];  
	  
	}
	
	/**
	 * 这个星期的星期天
	 * @$timestamp ，某个星期的某一个时间戳，默认为当前时间 
	 * @is_return_timestamp ,是否返回时间戳，否则返回时间格式
	 */   
	function thisSunday($timestamp=0,$is_return_timestamp=true){  
		 static $cache ;  
		 $id = $timestamp.$is_return_timestamp;  
		 if(!isset($cache[$id])){  
		 	 if(!$timestamp) $timestamp = time();  
		 	 $sunday = $this->thisMonday($timestamp) + /*6*86400*/518400;  
		 	 if($is_return_timestamp){  
		 	 	 $cache[$id] = $sunday;  
		 	 }else{  
		 	 	 $cache[$id] = date('Ymd',$sunday);  
		 	 }  
		 }  
		 return $cache[$id];  
	} 	

	/**
	 * 获取上周一
	 * @$timestamp ，某个星期的某一个时间戳，默认为当前时间
	 * @is_return_timestamp ,是否返回时间戳，否则返回时间格式  
	 */
	function lastMonday($timestamp=0,$is_return_timestamp=true){  
		 static $cache ;  
		 $id = $timestamp.$is_return_timestamp;  
		 if(!isset($cache[$id])){  
		 	 if(!$timestamp) $timestamp = time();  
		 	 $thismonday = $this->thisMonday($timestamp) - /*7*86400*/604800;  
		 	 if($is_return_timestamp){  
		 	 	 $cache[$id] = $thismonday;  
		 	 }else{  
		 	 	 $cache[$id] = date('Ymd',$thismonday);  
		 	 }  
		 }  
		 return $cache[$id];  
	}
  
	/**
	 * 上个星期天  
	 * @$timestamp ，某个星期的某一个时间戳，默认为当前时间
	 * @is_return_timestamp ,是否返回时间戳，否则返回时间格式  
	 */
	function lastSunday($timestamp=0,$is_return_timestamp=true){  
		 static $cache ;  
		 $id = $timestamp.$is_return_timestamp;  
		 if(!isset($cache[$id])){  
		 	 if(!$timestamp) $timestamp = time();  
		 	 $thissunday = $this->thisSunday($timestamp) - /*7*86400*/604800;  
		 	 if($is_return_timestamp){  
		 	 	 $cache[$id] = $thissunday;  
		 	 }else{  
		 	 	 $cache[$id] = date('Ymd',$thissunday);  
		 	 }  
		 }  
		 return $cache[$id];  
	}  

	
	static private $socketSrc = array();

	public function tcpClient($ip,$port,$data,$keep='N'){
		

		if(true || !isset(self::$socketSrc[$ip+':'+$port])){
			if (($socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false) {
				return n_state(FALSE, "创建SOCKET失败");
			}
			socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, array('sec'=>1, 'usec'=>0));
			socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, array('sec'=>1, 'usec'=>0));
			//socket_set_nonblock($socket);
			if(!socket_connect($socket,$ip,$port)){
				return n_state(FALSE, "连接失败:".socket_strerror(socket_last_error()));
			}
			self::$socketSrc[$ip+':'+$port] = $socket;
			//exit;
			//stream_set_blocking($socket,1); 
			socket_set_nonblock($socket);
			//exit;
		}else{
			$socket = self::$socketSrc[$ip+':'+$port];
			
		}
		//$data = str_replace(array("\n","\r"), "", $data);
		//echo $data."<br>";
		//echo strlen($data).'***';


		$length = strlen($data);
		socket_write($socket,"flag:start",strlen("flag:start"));
		$rs = socket_read($socket, 1024*2,PHP_NORMAL_READ);
		$i = 0;
		while (true) {
			// echo '-----';
			// echo $data;
			// echo $i++;
			$sent = socket_write($socket, $data, 2*1024);
			
			if ($sent === false) {
				socket_close($socket);
				//socket_shutdown(2);
				//echo '=====2===';
				return n_state(FALSE, "发送失败:".socket_strerror(socket_last_error()));
				//throw new PException("发送失败");
				//break;
			}
			$rs = socket_read($socket, 1024*2,PHP_NORMAL_READ);
	 
		
			if ($sent < $length) {
				$data = substr($data, $sent);
				$length -= $sent; 
			} else {
				//socket_write($socket,"\n",strlen("\n"));	
				//var_dump($rs);
				break;
			}
			 	 	  
		}


		socket_write($socket,"flag:end",strlen("flag:end"));
		$rs = socket_read($socket, 1024*2,PHP_NORMAL_READ);



		socket_write($socket,"flag:rs",strlen("flag:rs"));
		$rs = socket_read($socket, 1024*2,PHP_NORMAL_READ);




		if($sent === false) {
	 	 	socket_close($socket);
			//echo '====1====';
	 	 	return n_state(FALSE, "发送失败:".socket_strerror(socket_last_error()));
		}
		$data = "flag:close";
		$length = strlen($data);

		
		socket_write($socket,$data,$length);

		while(true) {
			$read = socket_read($socket, 1024*512,PHP_NORMAL_READ);
			if(empty($read)) break;
			if('flag:close'==trim($read)){
				socket_close($socket);
				return $read;
			}
			$rs .= $read;
		}

		socket_close($socket);
		if('Y'!=$keep){

		}
		return $rs;
	}
	public function tcpClientClose($ip, $port){
		if(!isset(self::$socketSrc[$ip+':'+$port])){
			return n_state(FALSE,"找不到创建的连接");
		}
		socket_close(self::$socketSrc[$ip+':'+$port]);
	}


	/**
	 * tcpClient2
	 *
	 * tcp 新的客户端连接
	 * 
	 * @param  string $controller 请求的controller
	 * @param  string $action	  请求的action
	 * @param  array $data	    请求的参数
	 * @param  string $ip	 	  请求的参数
	 * @param  int $port	    请求的参数
	 * @param  string $keep	    
	 * 
	 * @return string
	 */
	public function tcpClient2($controller, $action, $data, $ip, $port,  $keep='N', $timeout=1) {

		if(empty($controller) || empty($action) || !is_array($data) || empty($ip) || empty($port)) {
			return n_state(false, "参数错误，请检查参数的类型或个数");
		}

		if (($socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false) {
			return n_state(false, "创建SOCKET失败");
		}
		socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, array('sec' => $timeout, 'usec' => 0));
		socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, array('sec' => $timeout, 'usec' => 0));
		
		if(!socket_connect($socket, $ip, $port)){
			return n_state(false, "连接失败:".socket_strerror(socket_last_error()));
		}
		
		$buffer = array();
		$buffer[] = $controller;
		$buffer[] = $action;
		$buffer[] = str_replace(' ', '', json_encode($data));
		$buffer[] = "\r\n\r\n";

		$buffer = implode(' ', $buffer);

		$length = strlen($buffer);
		//发送数据
		while (true) {
			
			$sent = socket_write($socket, $buffer, $length);
			
			if (false === $sent) {
				socket_close($socket);
				
				return n_state(false, "发送失败:".socket_strerror(socket_last_error()));
				
			}
		
			if ($sent < $length) {
				$data = substr($data, $sent);
				$length -= $sent; 
			} else {
				break;
			}
			 	 	  
		}

		$read = socket_read($socket, 1024*512, PHP_BINARY_READ);
		
		if(false === $read) {
			return n_state(false, "接收数据失败:".socket_strerror(socket_last_error()));
		}
		socket_close($socket);
		
		return $read;
	}

	/**
	 * tcpClient3 测试用
	 *
	 * tcp 新的客户端连接
	 * 
	 * @param  string $controller 请求的controller
	 * @param  string $action	  请求的action
	 * @param  array $data	    请求的参数
	 * @param  string $ip	 	  请求的参数
	 * @param  int $port	    请求的参数
	 * @param  int $sec
	 * @param  int $usec    
	 * 
	 * @return string
	 */
	public function tcpClient3($controller, $action, $data, $ip, $port,  $sec=1, $usec=0) {

		if(empty($controller) || empty($action) || !is_array($data) || empty($ip) || empty($port)) {
			return n_state(false, "参数错误，请检查参数的类型或个数");
		}

		if (($socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false) {
			return n_state(false, "创建SOCKET失败");
		}
		socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, array('sec' => $sec, 'usec' => $usec));
		socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, array('sec' => $sec, 'usec' => $usec));
		
		if(!socket_connect($socket, $ip, $port)){
			return n_state(false, "连接失败:".socket_strerror(socket_last_error()));
		}
		
		$buffer = array();
		$buffer[] = $controller;
		$buffer[] = $action;
		$buffer[] = urlencode(json_encode($data));
		$buffer[] = "\r\n\r\n";

		$buffer = implode(' ', $buffer);

		$length = strlen($buffer);
		//发送数据
		while (true) {
			
			$sent = socket_write($socket, $buffer, $length);
			
			if (false === $sent) {
				socket_close($socket);
				
				return n_state(false, "发送失败:".socket_strerror(socket_last_error()));
				
			}
		
			if ($sent < $length) {
				$data = substr($data, $sent);
				$length -= $sent; 
			} else {
				break;
			}
		}

		$read = socket_read($socket, 1024*512, PHP_BINARY_READ);
		socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, array('sec' => 0, 'usec' => 1E4));
		foreach (range(1, 20) as $i) {
			$part = socket_read($socket, 1024*512, PHP_BINARY_READ);
			if (empty($part)) break;
			$read .= $part;
		}

		if(false === $read) {
			return n_state(false, "接收数据失败:".socket_strerror(socket_last_error()));
		}

		socket_close($socket);

		return $read;
	}
	
	
	public function watermark($img){
		
	}
	
	public function isWap(){
		if(stristr($_SERVER['HTTP_USER_AGENT'],'Mobile')){
			return true;
		}
		return false;
	}
	/**
	 * getLocalIp
	 *
	 * 获取本机地址
	 * 
	 * @return array
	 */
	public function getLocalIp() {
		$cmd = " /sbin/ifconfig | grep 'inet addr' | grep -v '127.0.0.1' | awk '{print $2}' | awk -F \":\" '{print $2}'";

		$fp = popen($cmd, 'r');

		if(!$fp) return false;

		$ips = array();
		while(!feof($fp)) {
			$ip = trim(fgets($fp));

			if(!empty($ip)) {
				$ips[] = trim($ip);	
			}
			
		}

		return $ips;
	}

	/**
	 * uintToInt
	 *
	 * 无符号整型转为符号整形(32位)
	 * 
	 * @param  int $int 整数
	 * @return int
	 */
	public function uintToInt($int) {
		if(!is_int($int)) return $int;

		$binary = sprintf('%032s', decbin($int));

		if($binary[0] == 0) return $int;

		$mask = substr($binary, 1);

		return bindec($mask) - pow(2, 31);
	}

	/**
	 * parseXml
	 *
	 * 解析XML为一个数组
	 * 
	 * @param  string $xml xml
	 * @return array
	 */
	public function parseXML($xml) {
		$xml = trim($xml);
		if(empty($xml) || !function_exists('simplexml_load_string')) return false;

		//兼容libxml2版本, 版本过低不支持GBK格式的文本
		if(false !== strpos($xml, "GBK")) {
			$xml = str_replace("GBK", "UTF8", $xml);
			$xml = mb_convert_encoding($xml, "UTF8", "GBK");
		}

		$data = simplexml_load_string($xml);

		if(false === $data) return false;

		return (array)$data;
	}
	
	/**
	 * curlMultiGet
	 *
	 * 通过GET并行请求(有一个请求成功就开始处理)
	 * 
	 * @param  array   $urls	   url 比如：array('http://m2.soho.com/open/')
	 * @param  array   $callbacks 每个URL对应的callback 函数，array(URL => array('object' => '', 'action' => ''));比如：array('http://m2.soho.com/open/' => array('object' => $this, 'action' => 'open')
	 * @param  integer $timeout   超时设置,单位：秒
	 * 
	 * @return array
	 */
	public function curlMultiGet($urls, $callbacks = array(), $timeout = 1) {

		if(!is_array($urls) || empty($urls)) return false;

		$queue = curl_multi_init();
		$map = array();

		foreach ($urls as $url) {
			$ch = curl_init();

			curl_setopt($ch, CURLOPT_URL, $url);
			curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
			curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
			curl_setopt($ch, CURLOPT_HEADER, 0);
			curl_setopt($ch, CURLOPT_NOSIGNAL, true);

			curl_multi_add_handle($queue, $ch);
			$map[(string) $ch] = $url;
		}

		$responses = array();
		do {
			while (($code = curl_multi_exec($queue, $active)) == CURLM_CALL_MULTI_PERFORM) ;

			if ($code != CURLM_OK) { break; }

			// a request was just completed -- find out which one
			while ($done = curl_multi_info_read($queue)) {

				// get the info and content returned on the request
				$header = curl_getinfo($done['handle']);
				$error = curl_error($done['handle']);
				$url = $map[(string) $done['handle']];
				$callback = $callbacks[$url];
				if(!empty($callback) && method_exists($callback['object'], $callback['action'])) {
					 $respond = call_user_func(array($callback['object'], $callback['action']), curl_multi_getcontent($done['handle']));
				} else {
					 $respond = curl_multi_getcontent($done['handle']);
				}

				$responses[$url] = compact('header', 'error', 'respond');

				// remove the curl handle that just completed
				curl_multi_remove_handle($queue, $done['handle']);
				curl_close($done['handle']);
			}

			// Block for data in / output; error handling is done by curl_multi_exec
			if ($active > 0) {
				curl_multi_select($queue, 0.5);
			}

		} while ($active);

		curl_multi_close($queue);
		return $responses;
	}

	/**
	 * curlClassicMultiGet
	 *
	 * 经典并行(等所有请求完成了才开始处理), 注：该方法主要用于测试比较
	 * 
	 * @param  array $urls 
	 * @return array
	 */
	public function curlClassicMultiGet($urls) {
		$mh = curl_multi_init();
		$curl_array = array();
		foreach($urls as $i => $url) {
			$curl_array[$i] = curl_init($url);
			curl_setopt($curl_array[$i], CURLOPT_RETURNTRANSFER, true);
			curl_multi_add_handle($mh, $curl_array[$i]);
		}
		$running = NULL;
		do {
			 usleep(10000);
			 curl_multi_exec($mh,$running);
		} while($running > 0);

		$res = array();
		foreach($urls as $i => $url) {
			 $res[$url] = curl_multi_getcontent($curl_array[$i]);
		}

		foreach($urls as $i => $url) {
			 curl_multi_remove_handle($mh, $curl_array[$i]);
		}
		curl_multi_close($mh);	    
		return $res; 
	}

	/**
	 * curlClassicMultiPost
	 *
	 * 经典并行(测试用)
	 * 
	 * @param  array  $urls 
	 * @param  array  $data 
	 * @param  integer $timeout
	 * 
	 * @return array
	 */
	public function curlClassicMultiPost($urls, $data, $timeout = 1) {
		$mh = curl_multi_init();
		$curl_array = array();
		foreach($urls as $i => $url) {
			$curl_array[$i] = curl_init($url);

			curl_setopt($curl_array[$i], CURLOPT_RETURNTRANSFER, true);
			curl_setopt($curl_array[$i], CURLOPT_TIMEOUT, $timeout);
			curl_setopt($curl_array[$i], CURLOPT_HEADER, 0);
			curl_setopt($curl_array[$i], CURLOPT_NOSIGNAL, true);
			curl_setopt($curl_array[$i], CURLOPT_POST, 1);
			curl_setopt($curl_array[$i], CURLOPT_POSTFIELDS, http_build_query($data));

			curl_multi_add_handle($mh, $curl_array[$i]);
		}
		$running = NULL;
		do {
			usleep(10000);
			curl_multi_exec($mh,$running);
		} while($running > 0);

		$res = array();
		foreach($urls as $i => $url) {
			$res[$url] = curl_multi_getcontent($curl_array[$i]);
		}

		foreach($urls as $i => $url){
			curl_multi_remove_handle($mh, $curl_array[$i]);
		}
		curl_multi_close($mh);	    
		return $res; 
	}

	/**
	 * curlMultiPost
	 *
	 * 通过POST并行请求
	 * 
	 * @param  array  $urls	   
	 * @param  array  $data	   POST的数据
	 * @param  array   $callbacks 每个请求对应的回调函数, array(URL => array('object' => '', 'action' => ''))
	 * @param  integer $timeout   超时设置，单位：秒
	 * @param  string  $host	   
	 * @param  integer $port	   
	 * 
	 * @return array
	 */
	public function curlMultiPost($urls, $data, $callbacks = array(), $timeout = 1, $host = '', $port = 0) {
		
		if(!is_array($urls) || empty($urls) || !is_array($data)) return false;

		$queue = curl_multi_init();
		$map = array();

		foreach ($urls as $url) {
			$ch = curl_init();

			curl_setopt($ch, CURLOPT_URL, $url);
			curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
			curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
			curl_setopt($ch, CURLOPT_HEADER, 0);
			curl_setopt($ch, CURLOPT_NOSIGNAL, true);

			if(!empty($port)){
			curl_setopt($ch, CURLOPT_PORT, $port);
			}
			if(!empty($host)){
			curl_setopt($ch, CURLOPT_HTTPHEADER, array("Host: {$host}"));
			}
			curl_setopt($ch, CURLOPT_POST, 1);
			curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));

			curl_multi_add_handle($queue, $ch);
			$map[(string) $ch] = $url;
		}

		$responses = array();
		do {
			while (($code = curl_multi_exec($queue, $active)) == CURLM_CALL_MULTI_PERFORM) ;

			if ($code != CURLM_OK) { break; }

			// a request was just completed -- find out which one
			while ($done = curl_multi_info_read($queue)) {

				// get the info and content returned on the request
				$header = curl_getinfo($done['handle']);
				$error = curl_error($done['handle']);

				$url = $map[(string) $done['handle']];
				$callback = $callbacks[$url]; 
				if(!empty($callback) && method_exists($callback['object'], $callback['action'])) {
					$respond = call_user_func(array($callback['object'], $callback['action']), curl_multi_getcontent($done['handle']));
				} else {
					$respond = curl_multi_getcontent($done['handle']);
				}

				$responses[$map[(string) $done['handle']]] = compact('header', 'error', 'respond');

				// remove the curl handle that just completed
				curl_multi_remove_handle($queue, $done['handle']);
				curl_close($done['handle']);
			}

			// Block for data in / output; error handling is done by curl_multi_exec
			if ($active > 0) {
				curl_multi_select($queue, 0.5);
			}

		} while ($active);

		curl_multi_close($queue);
		return $responses;
	}
}
